#include "lvgl_app/lvgl_pm/lvgl_pm.h"
#include "lvgl_app/lvgl_pm/pm_anima.h"
#include "lvgl_app/lvgl_pm/pm_utils.h"
#include "lvgl_app/lvgl_pm/pm_bar.h"

#include <stdlib.h>
#include <stdio.h>

/* 当前bug
当界面切换过快时会出现动画还未完全运行完就切换下一个界面
下方两个释放资源的回调无法执行，会出现内存泄露的问题
_disAppear_complete_cb
_back_disAppear_complete_cb
*/
/* 全局变量声明区域 */
int lv_pm_history_len;/* 该值是当前路由表保存了多少个界面的值  比如当前路由表使用了[0]， 该值就为1 */
lv_pm_page_t* lv_pm_router[LV_PM_PAGE_NUM];/* 页面管理数组 */
lv_pm_id_t lv_pm_history[LV_PM_PAGE_NUM];  /* 路由表 */
extern lv_obj_t* bakc_bar_cont_btn;
lv_pm_open_options_t options_default =
{
    .animation = LV_PM_ANIMA_POPUP,
    .direction = LV_PM_ANIMA_BOTTOM,
    .target = LV_PM_TARGET_NEW
};
lv_pm_open_options_t options_fade =
{
    .animation = LV_PM_ANIMA_FADE,
    .direction = LV_PM_ANIMA_BOTTOM,
    .target = LV_PM_TARGET_NEW
};
/* 静态变量声明区域 */
static lv_coord_t lv_pm_width;
static lv_coord_t lv_pm_height;
static lv_align_t lv_pm_align;
static lv_coord_t lv_pm_x_ofs;
static lv_coord_t lv_pm_y_ofs;
static lv_pm_id_t last_id = (lv_pm_id_t)-1; /* 用于记录当前界面的一个变量 防止当前界面打开自己 */
static lv_obj_t* screen = NULL;

/* open使用 页面已经被完整展示回调 */
static void _appear_complete_cb(lv_pm_page_t* pm_page, lv_pm_open_options_t options)
{
    lv_pm_printf("%s\r\n", __func__);
    if (pm_page->didAppear) {
        pm_page->didAppear(pm_page);
    }
    lv_pm_bar_control_fun(pm_page);
}
/* back使用 页面已经被完整展示回调 */
static void _back_appear_complete_cb(lv_pm_page_t* pm_page, lv_pm_open_options_t options)
{
    lv_pm_printf("%s\r\n", __func__);
    if (pm_page->didAppear) {
        pm_page->didAppear(pm_page);
    }
    lv_pm_bar_control_fun(pm_page);
}
/* open使用 页面已经被隐藏不可见 同时在这进行资源释放 */
static uint8_t _disAppear_complete_cb_flag = 0;
static void _disAppear_complete_cb(lv_pm_page_t* pm_page, lv_pm_open_options_t options)
{
    _disAppear_complete_cb_flag = 0;
    if (options.animation != LV_PM_ANIMA_POPUP) {
        lv_obj_add_flag(pm_page->page, LV_OBJ_FLAG_HIDDEN);
    }
    if (pm_page->didDisappear) {
        pm_page->didDisappear(pm_page);
    }
    lv_pm_printf("%s\r\n", __func__);
    switch (options.target)
    {
    case LV_PM_TARGET_SELF:
    case LV_PM_TARGET_RESET:
    {
        pm_page->unLoad(pm_page);
        if (pm_page->group)/* 对group进行释放 */
        {
            lv_group_del(pm_page->group);
            pm_page->group = NULL;
        }
        lv_obj_clean(pm_page->page);
        if (pm_page->user_data)/* 对user_data进行释放 */
        {
            lv_mem_free(pm_page->user_data);
            pm_page->user_data = NULL;
        }
    }
    break;
    default:
        break;
    }
}
/* back使用 页面已经被隐藏不可见 同时在这进行资源释放 */
static uint8_t _back_disAppear_complete_cb_flag = 0;
static void _back_disAppear_complete_cb(lv_pm_page_t* pm_page, lv_pm_open_options_t options)
{
    _back_disAppear_complete_cb_flag = 0;
    lv_obj_add_flag(pm_page->page, LV_OBJ_FLAG_HIDDEN);
    if (pm_page->didDisappear) {
        pm_page->didDisappear(pm_page);
    }
    lv_pm_printf("%s\r\n", __func__);
    pm_page->unLoad(pm_page);
    if (pm_page->group)/* 对group进行释放 */
    {
        lv_group_del(pm_page->group);
        pm_page->group = NULL;
    }
    if (pm_page->user_data)/* 对user_data进行释放 */
    {
        lv_mem_free(pm_page->user_data);
        pm_page->user_data = NULL;
    }
    lv_obj_clean(pm_page->page);
}


static lv_group_t* lv_pm_create_group(void)
{
    lv_group_t* group;
    /* 创建一个输入设备组 */
    //if (!lv_pm_group)
    //{
    //    lv_pm_group = lv_group_get_default();
    //    if (!lv_pm_group)
    //    {
    //        lv_pm_group = lv_group_create();
    //        if (lv_pm_group)
    //        {
    //            lv_group_set_default(lv_pm_group);
    //        }
    //    }
    //}
    group = lv_group_create();

    return group;
}
#ifdef user_lv_simulator
extern lv_indev_t* lv_win32_pointer_device_object;
extern lv_indev_t* lv_win32_keypad_device_object;
extern lv_indev_t* lv_win32_encoder_device_object;
void lv_pm_set_group_default(lv_group_t* group)
{
    lv_group_set_default(group);
    lv_indev_set_group(lv_win32_pointer_device_object, group);
    lv_indev_set_group(lv_win32_keypad_device_object, group);
    lv_indev_set_group(lv_win32_encoder_device_object, group);
}
#else
extern lv_indev_t* indev_encoder;
static void lv_pm_set_group_default(lv_group_t* group)
{
    lv_group_set_default(group);
    lv_indev_set_group(indev_encoder, group);

}
#endif
int lv_pm_set_page_size_default(lv_coord_t width, lv_coord_t height)
{
    lv_pm_width = width;
    lv_pm_height = height;

    return 0;
}
int lv_pm_set_page_default(lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs)
{
    lv_pm_align = align;
    lv_pm_x_ofs = x_ofs;
    lv_pm_y_ofs = y_ofs;
    return 0;
}

uint8_t lv_pm_init(void)
{
    lv_pm_history_len = 0;
    for (int i = 0; i < LV_PM_PAGE_NUM; i++)
    {
        lv_pm_router[i] = NULL;
    }
    lv_obj_set_style_bg_color(lv_scr_act(), lv_color_make(0, 0, 0), LV_PART_MAIN);/* 设置活动层颜色 */
    screen = lv_scr_act();
    /* 禁止屏幕滚动 */
    lv_obj_clear_flag(screen, LV_OBJ_FLAG_SCROLLABLE);
    /* 创建状态栏 */
#if LV_PM_USE_STA_BAR == 1
    lv_pm_create_status_bar();
#endif

#if LV_PM_USE_BACK_BAR == 1
    lv_pm_create_back_bar();
#endif
    /* 设定默认的页面大小 */
    lv_pm_set_page_size_default(LV_HOR_RES, LV_VER_RES);
    //lv_pm_set_page_size_default(LV_HOR_RES, LV_VER_RES - status_bar_y_default);
    /* 设定默认的页面位置 */
    lv_pm_set_page_default(LV_ALIGN_BOTTOM_MID, 0, 0);

    // turn off the scroll bar
    lv_obj_set_scrollbar_mode(screen, LV_SCROLLBAR_MODE_OFF);
    /* 对动画中所用资源进行创建 */
    lvgl_pm_anima_init();

#ifdef user_lv_simulator
    /* 创建一些hal的文件 */
    #include "lvgl_app/Hal_Exp/Hal_Exp_Variable.h"
    lv_pm_hal_Exp_in_init();
    lv_pm_hal_Exp_out_init();
#endif

    return 0;
}

/* 页面创建，你可以在这里执行初始化 */
static int8_t lv_pm_set_onLoad(void *page, lv_pm_lifecycle fun)
{
    if (page != NULL && fun != NULL)
    {
        lv_pm_get_pm_page(page)->onLoad = fun;
        return 0;
    }
    else
    {
        LV_LOG_ERROR("%s is Err (NULL)\r\n", __func__);
        return -1;
    }
}
/* 页面即将被展示 */
static int8_t lv_pm_set_willAppear(void* page, lv_pm_lifecycle fun)
{
    if (page != NULL && fun != NULL)
    {
        lv_pm_get_pm_page(page)->willAppear = fun;
        return 0;
    }
    else
    {
        LV_LOG_ERROR("%s is Err (NULL)\r\n", __func__);
        return -1;
    }
}
/* 页面已经被完整展示 */
static int8_t lv_pm_set_didAppear(void* page, lv_pm_lifecycle fun)
{
    if (page != NULL && fun != NULL)
    {
        lv_pm_get_pm_page(page)->didAppear = fun;
        return 0;
    }
    else
    {
        LV_LOG_ERROR("%s is Err (NULL)\r\n", __func__);
        return -1;
    }
}
/* 页面即将被隐藏 */
static int8_t lv_pm_set_willDisappear(void* page, lv_pm_lifecycle fun)
{
    if (page != NULL && fun != NULL)
    {
        lv_pm_get_pm_page(page)->willDisappear = fun;
        return 0;
    }
    else
    {
        LV_LOG_ERROR("%s is Err (NULL)\r\n", __func__);
        return -1;
    }
}
/* 页面已经被隐藏不可见 */
static int8_t lv_pm_set_didDisappear(void* page, lv_pm_lifecycle fun)
{
    if (page != NULL && fun != NULL)
    {
        lv_pm_get_pm_page(page)->didDisappear = fun;
        return 0;
    }
    else
    {
        LV_LOG_ERROR("%s is Err (NULL)\r\n", __func__);
        return -1;
    }
}
/* 页面被关闭，你需要在这里释放所有临时内存，否则可能存在泄漏 */
static int8_t lv_pm_set_unLoad(void* page, lv_pm_lifecycle fun)
{
    if (page != NULL && fun != NULL)
    {
        lv_pm_get_pm_page(page)->unLoad = fun;
        return 0;
    }
    else
    {
        LV_LOG_ERROR("%s is Err (NULL)\r\n", __func__);
        return -1;
    }
}
/* 让界面打开后聚焦这个对象 */
static int8_t lv_pm_set_focus_obj(void* page, lv_obj_t* obj)
{
    if (page != NULL && obj != NULL)
    {
        lv_pm_get_pm_page(page)->focus_obj = obj;
        return 0;
    }
    else
    {
        LV_LOG_ERROR("%s is Err (NULL)\r\n", __func__);
        return -1;
    }
}
/* 是否使能状态栏 true 是开启 false 是关闭 */
static int8_t lv_pm_set_status_bar(void* page, bool Enable)
{
    if (page != NULL)
    {
        if (Enable == false)
        {
            lv_pm_get_pm_page(page)->status_bar = true;/* 默认是0 也就是开启， 所以这里需要！ */
        }
        else
        {
            lv_pm_get_pm_page(page)->status_bar = false;/* 默认是0 也就是开启， 所以这里需要！ */
        }

        return 0;
    }
    else
    {
        LV_LOG_ERROR("%s is Err (NULL)\r\n", __func__);
        return -1;
    }
}
/* 是否使能返回栏 true 是开启 false 是关闭*/
static int8_t lv_pm_set_back_bar(void* page, bool Enable)
{
    if (page != NULL)
    {
        if (Enable == false)
        {
            lv_pm_get_pm_page(page)->back_bar = true;/* 默认是0 也就是开启， 所以这里需要！ */
        }
        else
        {
            lv_pm_get_pm_page(page)->back_bar = false;/* 默认是0 也就是开启， 所以这里需要！ */
        }
        return 0;
    }
    else
    {
        LV_LOG_ERROR("%s is Err (NULL)\r\n", __func__);
        return -1;
    }
}

/*这个函数只是注册界面 并不会创建界面 */
static lv_pm_page_t* lv_pm_create_page(lv_pm_id_t id, lv_pm_lifecycle onLoad, lv_pm_lifecycle unLoad)
{
    lv_pm_page_t* pm_page = (lv_pm_page_t*)lv_mem_alloc(sizeof(lv_pm_page_t));
    if (pm_page == NULL) {
        return NULL;
    }
    memset(pm_page, 0, sizeof(lv_pm_page_t));

    lv_pm_router[id] = pm_page;

    lv_obj_t* page = lv_obj_create(screen);
    // reset style. border radius etc...
    pm_reset_style(page);
    lv_obj_add_flag(page, LV_OBJ_FLAG_HIDDEN);
    lv_obj_set_size(page, lv_pm_width, lv_pm_height);
    lv_obj_align(page, lv_pm_align, lv_pm_x_ofs, lv_pm_y_ofs);

    pm_page->page = page;

    lv_pm_set_onLoad(pm_page, onLoad);
    lv_pm_set_unLoad(pm_page, unLoad);

    return pm_page;
}

/* 打开并向打开的界面写入一个用户数据 */
static uint8_t lv_pm_open_page_user(lv_pm_id_t id, lv_pm_open_options_t* behavior, void* user_data)
{
    if (lv_pm_router[id] == 0) {
        return 4;
    }
    if (lv_pm_history_len == LV_PM_PAGE_NUM) {
        return 5;
    }
    if (last_id == id) {/*禁止重复打开同一个界面*/
        return 6;
    }
    else
    {
        last_id = id;
    }
    lv_pm_printf("%s\n", __func__);
    lv_pm_history[lv_pm_history_len] = id;
    lv_pm_page_t* pm_page = lv_pm_router[id];
    lv_obj_t* page = pm_page->page;

    if (behavior) {
        pm_page->_options = *behavior;
    }
    pm_page->_back = false;

    if (lv_pm_history_len > 0)
    {
        //获取上一个界面，接下来将对上一个界面注册回调
        static lv_pm_page_t* last_page;/* 记录上一个界面的信息 */
        if (_disAppear_complete_cb_flag == 1)/* 为1时表示上个界面的释放操作并没有执行 得优先执行一次 防止内存泄露 */
        {
            _disAppear_complete_cb(last_page, last_page->_options);
        }
        _disAppear_complete_cb_flag = 1;
        last_page = lv_pm_router[id];/* 更新保存上一次的数据 */

        lv_pm_page_t* prev_pm_page;/* 记录上一个界面的信息 */
        lv_pm_id_t pid = lv_pm_history[lv_pm_history_len - 1];
        prev_pm_page = lv_pm_router[pid];
        prev_pm_page->_back = false;
        /* 对切进后台的页面先禁用输入设备*/
        //lv_group_del(lv_pm_group);
        lv_obj_clear_flag(prev_pm_page->page, LV_OBJ_FLAG_CLICKABLE);
        /* 再进行隐藏 */
        if (prev_pm_page->willDisappear) {
            prev_pm_page->willDisappear(prev_pm_page);
        }
        _pm_anima_disAppear(prev_pm_page, &pm_page->_options, _disAppear_complete_cb);
    }

    if (_back_disAppear_complete_cb_flag == 1)/* 打开新界面时需要查看返回操作是否完成否则可能会出现内存泄露 */
    {
        _back_disAppear_complete_cb(lv_pm_router[lv_pm_history[lv_pm_history_len]], lv_pm_router[lv_pm_history[lv_pm_history_len]]->_options);
    }
    if (behavior)
    {
        switch (behavior->target)
        {
        case LV_PM_TARGET_SELF:
        {
            if (lv_pm_history_len == 0)
            {
                lv_pm_history_len++;
            }
            else
            {
                lv_pm_history[lv_pm_history_len - 1] = lv_pm_history[lv_pm_history_len];
            }
        }
        break;
        case LV_PM_TARGET_RESET:/* 销毁所有界面路由表 再打开一个新的界面 */
        {
            if (lv_pm_history_len >= 2)/* 有两个界面的时候才需要销毁 */
            {
                lv_pm_history_len = lv_pm_history_len - 2;/* -1的界面会被 _disAppear_complete_cb 销毁 */
                for (int i = lv_pm_history_len; i >= 0; i--)
                {
                    lv_obj_clean(lv_pm_router[i]->page);
                }
            }

            /* 重新设置路由表 */
            lv_pm_history_len = 0;
            lv_pm_history[lv_pm_history_len] = id;
        }
        break;
        case LV_PM_TARGET_NEW:/* 新建一个界面 路由表增加 */
        default:
        {
            lv_pm_history_len++;
        }
        break;
        }
    }
    else
    {
        lv_pm_history_len++;
    }
    /* 设定输入设备组 */
    pm_page->group = lv_pm_create_group();
#if LV_PM_USE_BACK_BAR == 1
    if (pm_page->back_bar == 0)
    {
        lv_group_add_obj(pm_page->group, bakc_bar_cont_btn);/* 将top界面的返回按键也加入组内 */
    }
#endif

    lv_pm_set_group_default(pm_page->group);
    //(prev_pm_page->status_bar) << 1 | (prev_pm_page->back_bar);/*获取状态栏的状态*/
    /* 将user_data传给 pm_page */
    if (user_data != NULL)
    {
        lv_mem_free(pm_page->user_data);
        pm_page->user_data = user_data;
    }
    pm_page->onLoad(pm_page);
    if (pm_page->focus_obj) {
        lv_group_focus_obj(pm_page->focus_obj);
    }
    else
    {
        lv_group_focus_obj(lv_obj_get_child(page, 0));

    }
    lv_obj_clear_flag(page, LV_OBJ_FLAG_HIDDEN);
    if (pm_page->willAppear) {
        pm_page->willAppear(pm_page);
    }
    _pm_anima_appear(pm_page, &pm_page->_options, _appear_complete_cb);
    lv_pm_printf("lv_pm_history_len -> %d\r\n", lv_pm_history_len);
    return 0;
}

/*这个函数只是是打开注册界面 该操作才会真正的创建界面
2023-1-6记录 重复打开同一个界面会内存泄露需要修改掉*/
static uint8_t lv_pm_open_page(lv_pm_id_t id, lv_pm_open_options_t* behavior)
{
    return lv_pm_open_page_user(id, behavior, NULL);
}

static uint8_t lv_pm_back_user(void* user_data)
{
    if (lv_pm_history_len < 2) {
        return 0;
    }

    lv_pm_printf("%s->%d\n", __func__, lv_pm_history_len);
    last_id = lv_pm_history[lv_pm_history_len];

    /* 先关闭当前界面 */
    static lv_pm_page_t* pm_page = NULL;/* 记录上一个界面的信息 */
    if (_back_disAppear_complete_cb_flag == 1)/* 为1时表示上个界面的释放操作并没有执行 得优先执行一次 防止内存泄露 */
    {
        _back_disAppear_complete_cb(pm_page, pm_page->_options);
    }
    _back_disAppear_complete_cb_flag = 1;

    lv_pm_id_t pid = lv_pm_history[lv_pm_history_len - 1];
    pm_page = lv_pm_router[pid];
    pm_page->_back = true;

    if (pm_page->willDisappear) {
        pm_page->willDisappear(pm_page);
    }
    _pm_anima_disAppear(pm_page, &pm_page->_options, _back_disAppear_complete_cb);

    /* 再打开以前的界面 */
    lv_pm_history_len--;
    lv_pm_id_t prev_pid = lv_pm_history[lv_pm_history_len - 1];
    lv_pm_page_t* prev_pm_page = lv_pm_router[prev_pid];
    /* 切换输入设备组 */
    lv_pm_set_group_default(prev_pm_page->group);
    prev_pm_page->_back = true;
    /* 将user_data传给 pm_page */
    if (user_data != NULL)
    {
        lv_mem_free(pm_page->user_data);
        pm_page->user_data = user_data;
    }
    if (prev_pm_page->willAppear) {
        prev_pm_page->willAppear(prev_pm_page);
    }
    lv_obj_clear_flag(prev_pm_page->page, LV_OBJ_FLAG_HIDDEN);
    _pm_anima_appear(prev_pm_page, &pm_page->_options, _back_appear_complete_cb);

    return 0;

}

static uint8_t lv_pm_back(void)
{
    return lv_pm_back_user(NULL);
}


static uint8_t lv_pm_back_id(lv_pm_id_t id)/*返回到指定的ID 该ID必须是路由表存在的历史记录 否则无响应  2023-1-12日对应完毕 可用此函数返回到主界面等特殊操作*/
{
    int match_index;
    for (match_index = 0; match_index < lv_pm_history_len - 1 && match_index < LV_PM_PAGE_NUM; match_index++)/* 扫描到本ID为止 */
    {
        if (lv_pm_history[match_index] == id)
        {
            break;
        }
    }
    if (match_index < lv_pm_history_len - 1)
    {
        lv_pm_printf("match ID[%d] -> %d\r\n", match_index, lv_pm_history[match_index]);
        if (match_index == lv_pm_history_len - 2)/* 这种情况直接调用back即可 */
        {
            /* 查询到的路由表就在本界面的上一个 直接back即可 */
            lv_pm_back();
        }
        else
        {
            last_id = lv_pm_history[lv_pm_history_len];

            /* 先关闭当前界面 */
            lv_pm_id_t pid = lv_pm_history[lv_pm_history_len - 1];
            lv_pm_page_t* pm_page = lv_pm_router[pid];
            pm_page->_back = true;

            if (pm_page->willDisappear) {
                pm_page->willDisappear(pm_page);
            }
            _pm_anima_disAppear(pm_page, &pm_page->_options, _back_disAppear_complete_cb);

            /* 再直接释放中间的被跳过的界面 */
            for (int i = match_index + 1; i <= lv_pm_history_len - 2; i++)
            {
                lv_pm_id_t skip_pid = lv_pm_history[i];
                lv_pm_page_t* skip_pm_page = lv_pm_router[skip_pid];
                skip_pm_page->_back = true;

                if (skip_pm_page->willDisappear) {
                    skip_pm_page->willDisappear(skip_pm_page);
                }
                /* 直接调用动画的回调 进行各种资源释放 */
                _back_disAppear_complete_cb(skip_pm_page, skip_pm_page->_options);
            }

            /* 再打开以前的界面 */
            lv_pm_history_len = match_index + 1;/* 将查询到的ID赋值给路由表查询位置 */
            lv_pm_history[lv_pm_history_len] = last_id;/* 移动当前关闭的界面到新位置 */
            lv_pm_id_t prev_pid = lv_pm_history[lv_pm_history_len - 1];
            lv_pm_page_t* prev_pm_page = lv_pm_router[prev_pid];
            /* 切换输入设备组 */
            lv_pm_set_group_default(prev_pm_page->group);
            prev_pm_page->_back = true;

            if (prev_pm_page->willAppear) {
                prev_pm_page->willAppear(prev_pm_page);
            }
            lv_obj_clear_flag(prev_pm_page->page, LV_OBJ_FLAG_HIDDEN);
            _pm_anima_appear(prev_pm_page, &pm_page->_options, _back_appear_complete_cb);
        }
    }
    else
    {
        lv_pm_printf("%s, No ID found[%d]\r\n", __func__, id);
    }

    return 0;
}

static void * lv_pm_get_user(void)
{
    /* 获取到本界面的pege */
    lv_pm_id_t pid = lv_pm_history[lv_pm_history_len - 1];
    lv_pm_page_t* pm_page = lv_pm_router[pid];

    return pm_page->user_data;
}

static void lv_pm_free_user(void)
{
    /* 获取到本界面的pege */
    lv_pm_id_t pid = lv_pm_history[lv_pm_history_len - 1];
    lv_pm_page_t* pm_page = lv_pm_router[pid];

    lv_mem_free(pm_page->user_data);
    pm_page->user_data = NULL;
}

/* 创建pege时使用  */
const lv_pm_create_t lv_pm_create =
{
    .create        = lv_pm_create_page,
    .onLoad        = lv_pm_set_onLoad,
    .willAppear    = lv_pm_set_willAppear,
    .didAppear     = lv_pm_set_didAppear,
    .willDisappear = lv_pm_set_willDisappear,
    .didDisappear  = lv_pm_set_didDisappear,
    .unLoad        = lv_pm_set_unLoad,
    .focus_obj     = lv_pm_set_focus_obj,
    .status_bar    = lv_pm_set_status_bar,
    .back_bar      = lv_pm_set_back_bar
};
/* 控制page时使用 */
const lv_pm_control_t lv_pm_control =
{
    .open = lv_pm_open_page,
    .open_user = lv_pm_open_page_user,
    .back = lv_pm_back,
    .back_user = lv_pm_back_user,
    .back_id = lv_pm_back_id,
    .get_user = lv_pm_get_user,
    .free_user = lv_pm_free_user
};
